﻿using System;
using System.Collections.Generic; 
using Csu.Modsim.ModsimModel; 
using ASquared.ModelOptimization;
using ASquared.SymbolicMath;
using ASquared; 

namespace iwpm.optimization
{
    public class EnvVsHydro : HydroTargetSeeker, IConditionalGradientSolvableFunction
    {
        private EnvVsHydroInputs _inputs;
        private Model _model; 

        public EnvVsHydro(Model model, EnvVsHydroInputs inputs)
            : base(model, inputs.HydropowerWeight) 
        {
            _model = model;
            _inputs = inputs; 
        }

        /// <summary>
        /// Fills the function mask with the new variables added by the environmental modeling function
        /// </summary>
        private void SetupMask()
        {
            // Variables
            Matrix currMask = base.variableMask; 
            HashSet<string> allSymbols = new HashSet<string>();

            // Get all the symbols within the environtmental modeling function
            foreach (Symbol s in _inputs.EnvironmentalModel.Mapper.Symbols)
                foreach (string var in s.Variables())
                    allSymbols.Add(var.Replace("q_","")); 

            // Get the number from each variable ('X' from "q_X"), which is the number within the mask
            int lnum; 
            foreach (string sym in allSymbols)
                if (int.TryParse(sym, out lnum))
                    currMask[lnum - 1] = 1; 

            // Fill the nonlinear mask with the new mask
            base.variableMask = currMask;
        }

        public override void Initialize()
        {
            base.Initialize();
            SetupMask(); 
        }

        public EnvVsHydroInputs Inputs
        {
            get
            {
                return _inputs; 
            }
        }

        public override Symbol fxn
        {
            get
            {
                double currval = _inputs.EnvironmentalModel.EvaluateCurrent(0);
                if (_inputs.EnvironmentalThresholds.IsOutsideBounds(currval))
                {
                    double bound = _inputs.EnvironmentalThresholds.ClosestBoundedValue(currval);
                    return base.fxn
                        + _inputs.EnvironmentalWeight
                        * ((_inputs.EnvironmentalModel.GetCurrent(0, true) - bound) ^ 2);
                }
                else
                    return base.fxn; 
            }
        }

        
    }
}
